#  Copyright (c) 1997-2011
#  Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Darmstadt, Germany)
#  http://www.polymake.de
#
#  This program is free software; you can redistribute it and/or modify it
#  under the terms of the GNU General Public License as published by the
#  Free Software Foundation; either version 2, or (at your option) any
#  later version: http://www.gnu.org/licenses/gpl.txt.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#-------------------------------------------------------------------------------
#  $Project: polymake $$Id: graph_types 10133 2011-04-06 14:12:51Z herr $


declare property_type Directed : c++ (special => 'Directed', include => ["polymake/Graph.h"]);

declare property_type Undirected : c++ (special => 'Undirected', include => ["polymake/Graph.h"]);

declare property_type EdgeList<*> : c++;

declare property_type EdgeIterator<*> : Iterator : c++ {

   method from_node() : c++;

   method to_node() : c++;
}

function entire(EdgeList) : c++ : returns(EdgeIterator<*>);

##################################################################################

declare property_type Graph<Dir=Undirected> : c++ (include => ["polymake/Graph.h"], operators => '@sets:wary == !=') {

   user_method nodes() : c++;

   user_method edges() : c++;

   user_method add_node() : non_const : c++;

   user_method node_exists($) : wary : c++;

   user_method delete_node($) : non_const : wary : void : c++;

   user_method edge($$) : non_const : wary : c++;

   user_method delete_edge($$) : non_const : void : wary : c++;

   user_method contract_edge($$) : non_const : void : wary : c++;

   user_method squeeze() : non_const : void : c++;

   user_method edge_exists($$) : wary : c++;

   user_method in_edges($) : wary : c++ : returns(EdgeList<*>);

   user_method out_edges($) : wary : c++ : returns(EdgeList<*>);


   # Gives the indices of the nodes adjacent to //node//.
   # @param Int node
   user_method adjacent_nodes($) : wary : lvalue_opt : c++;

   # Gives the indices of the nodes that have an edge to //node//.
   # @param Int node
   user_method in_adjacent_nodes($) : wary : lvalue_opt : c++;

   # Gives the indices of the nodes with an edge arriving from //node//.
   # @param Int node
   user_method out_adjacent_nodes($) : wary : lvalue_opt : c++;

   user_method in_degree($) : wary : c++;

   user_method out_degree($) : wary : c++;

   user_method degree($) : wary : c++;

   user_method has_gaps() : c++;

   user_method dim() : c++;

   method construct(Int) : c++;

   method construct(IncidenceMatrix) : c++;

   sub toXML {
      my $g=shift;
      if ($g->has_gaps) {
	 my ($writer, @attr)=@_;
	 $writer->startTag("m", @attr, dim => $g->dim);
	 my $type=Int->type;
	 for (my $n=entire(common::nodes($g)); $n; ++$n) {
	    trivialArray_toXML($type, $n->out_adjacent_nodes, $writer, i=>$$n);
	 }
	 $writer->endTag("m");
      } else {
	 my $am=adjacency_matrix($g);
	 $am->type->toXML->($am,@_);
      }
   }

   method init_node_map(*:lvalue:wary) : void : c++;

   method init_edge_map(*:lvalue:wary) : void : c++;
}


# @category Graph operations

user_function adjacency_matrix(Graph:lvalue_opt) : c++;

function permuted_nodes(Graph, *) : c++;

function renumber_nodes(Graph) : c++;


# @category Graph operations

user_function edges(Graph) : c++ : returns(EdgeList<*>);

declare property_type NodeSet<*> : c++;

declare property_type NodeIterator<*> : Iterator : c++ {

   method out_edges() : c++ : returns(EdgeList<*>);

   method in_edges() : c++ : returns(EdgeList<*>);

   method adjacent_nodes() : c++;

   method out_adjacent_nodes() : c++;

   method in_adjacent_nodes() : c++;

   method degree() : c++;

   method in_degree() : c++;

   method out_degree() : c++;
}


# @category Graph operations

user_function nodes(Graph) : c++ : returns(NodeSet<*>);

function entire(NodeSet) : c++ : returns(NodeIterator<*>);

# the maps may contain gaps, hence got to use iterators
sub equal_maps {
   my ($elem_proto, $m1, $m2)=@_;
   @$m1==@$m2 and do {
      for (my ($it1,$it2)=(entire($m1), entire($m2)); $it1; ++$it1, ++$it2) {
	 $elem_proto->equal->($$it1, $$it2) or return 0;
      }
      1
   }
}

declare property_type NodeMap<Dir,Element> : Array<Element> : \
   c++ ( include => ["polymake/Graph.h"], default_constructor => 0 ) {

   method construct(Graph<Dir>) : c++;

   method construct(Graph<Dir>, $@) {
      my ($proto, $graph)=splice @_,0,2;
      CPlusPlus::assign_any($proto->construct->($graph), @_);
   }

   method equal { equal_maps((shift)->param->[1],@_); }
}

declare property_type EdgeMap<Dir,Element> : Array<Element> : \
   c++ ( include => ["polymake/Graph.h"], default_constructor => 0 ) {

   method construct(Graph<Dir>) : c++;

   method construct(Graph<Dir>, $@) {
      my ($proto, $graph)=splice @_,0,2;
      CPlusPlus::assign_any($proto->construct->($graph), @_);
   }

   method equal { equal_maps((shift)->param->[1],@_); }

   method operator($,$) : lvalue_opt : wary : c++;
}

declare property_type NodeHashMap<Dir,Element> : \
   c++ ( include => ["polymake/Graph.h"], default_constructor => 0 ) {

   method construct(Graph<Dir>) : c++;

   method construct(Graph<Dir>, $@) {
      my ($proto, $graph)=splice @_,0,2;
      CPlusPlus::assign_any($proto->construct->($graph), @_);
   }

   method equal { equal_maps((shift)->param->[1],@_); }
}

declare property_type EdgeHashMap<Dir,Element> : \
   c++ ( include => ["polymake/Graph.h"], default_constructor => 0 ) {

   method construct(Graph<Dir>) : c++;

   method construct(Graph<Dir>, $@) {
      my ($proto, $graph)=splice @_,0,2;
      CPlusPlus::assign_any($proto->construct->($graph), @_);
   }

   method equal { equal_maps((shift)->param->[1],@_); }

   method operator($,$) : non_const : wary : c++;

   method find($,$) : wary : c++;

   method erase($,$) : non_const : void : wary : c++;
}

function createNodeMap<Element,Dir>(Graph<Dir>) { new NodeMap<Dir,Element>(shift) }

function createEdgeMap<Element,Dir>(Graph<Dir>) { new EdgeMap<Dir,Element>(shift) }

function createNodeHashMap<Element,Dir>(Graph<Dir>) { new NodeHashMap<Dir,Element>(shift) }

function createEdgeHashMap<Element,Dir>(Graph<Dir>) { new EdgeHashMap<Dir,Element>(shift) }


# @category Graph operations

user_function induced_subgraph(Graph:wary, *) : c++ ( include => ["polymake/IndexedSubgraph.h"] );


# @category Graph operations
# @param Graph graph
# @tparam Coord coordinate type for the resulting matrix
# @return SparseMatrix
# node-edge incidence matrix of a graph
user_function node_edge_incidences<Coord=Int>(Graph) : c++ ( include => ["polymake/node_edge_incidences.h"] );

# Local Variables:
# mode: perl
# c-basic-offset:3
# End:
